using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;

public class GenericManager <type>  	where type : LoadableJSONObject, new(){
	public string name;
	public string url;
	
	public static string ValidName(string a)
	{
		string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
		Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
		return r.Replace(a, "").TrimEnd(new char[]{'.'});
	}
	
	//objects in the manifest with true markers are custom and can be deleted.
	Dictionary<string,bool> _objectManifest;
	Dictionary<string,bool> objectManifest
	{
		get
		{
			if(_objectManifest == null)
			{
				_objectManifest = new Dictionary<string, bool>();
			}
			return _objectManifest;
		}
	}
	
	public bool isCustom(string name)
	{
		if(objectManifest.ContainsKey(name))
			return objectManifest[name];
		return false;
	}
	
	
	public GenericManager(string typeName)
	{
		name = typeName;
		#if UNITY_EDITOR
	 	url = Application.dataPath + "\\"+ name +"\\";
		#else
		url = Application.persistentDataPath + "/" + name + "/";
		#endif
		
		if(!System.IO.Directory.Exists(url))
			System.IO.Directory.CreateDirectory(url);
	}
	
	public Dictionary<string,string> _index;
	
	public Dictionary<string,string> index
	{
		get
		{
			if(_index == null)
				LoadIndex();
			
			return _index;
		}
	}
	
	public void WriteIntoExtraFile(string fileName, object content)
	{
		System.IO.FileInfo info = new System.IO.FileInfo(url + fileName +"_extraData.json");
		if(info.Exists)
		{
			info.Delete();
		}
		
		System.IO.StreamWriter writer = info.CreateText();
		
		writer.Write(MiniJSON.Json.Serialize(content));
		
		writer.Close();
	}
	
	public object LoadExtraFile(string fileName)
	{
		System.IO.FileInfo info = new System.IO.FileInfo(url + fileName +"_extraData.json");
		if(info.Exists)
		{
			System.IO.StreamReader file = info.OpenText();
			string json = file.ReadToEnd();
			file.Close();
			object temp = MiniJSON.Json.Deserialize(json);
			return temp;
		}
		
		return null;
	}
	
	void LoadIndex()
	{
		_index = new Dictionary<string,string>();
		
		System.IO.FileInfo info = new System.IO.FileInfo(url + name +"Index.json");
		if(info.Exists)
		{
			System.IO.StreamReader file = info.OpenText();
			string json = file.ReadToEnd();
			Dictionary<string,object> objects = MiniJSON.Json.Deserialize(json) as Dictionary<string,object>;
			foreach(KeyValuePair<string,object> obj in objects)
			{	
				_index.Add(obj.Key,obj.Value as string);
				objectManifest.Add(obj.Key,false);
			}
			
			file.Close();
		}
		else
		{
			System.IO.StreamWriter writer = info.CreateText();
			
			Dictionary<string,string> dict = new Dictionary<string,string>();
			
			System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(url);
			foreach(System.IO.FileInfo file in d.GetFiles())
			{
				if(file.Name != (name +"Index.json") && file.Name != (name +"Index_custom.json") && !file.Name.Contains("_extraData.json"))
				{
					Debug.Log(file.Name);
					StreamReader sr = file.OpenText();
					string jsonBlob = sr.ReadToEnd();
					Dictionary<string,object> i = MiniJSON.Json.Deserialize(jsonBlob) as Dictionary<string,object>;
					if(!i.ContainsKey("custom") || (i.ContainsKey("custom") && !bool.Parse(i["custom"] as string)))
					{
						_index.Add(file.Name.Replace(".json",""), i["name"] as string);
						objectManifest.Add(file.Name.Replace(".json",""), false); 
						dict.Add(file.Name.Replace(".json",""), i["name"] as string);
					}
					sr.Close();
				}
			}
			
			string json = MiniJSON.Json.Serialize(dict);
			
			writer.WriteLine(json);
			
			writer.Close();
		}
		
		info = new System.IO.FileInfo(url + name +"Index_custom.json");
		if(info.Exists)
		{
			using(System.IO.StreamReader file = info.OpenText())
			{
				string json = file.ReadToEnd();
				Dictionary<string,object> objects = MiniJSON.Json.Deserialize(json) as Dictionary<string,object>;
				
				foreach(KeyValuePair<string,object> obj in objects)
				{	
					_index.Add(obj.Key,obj.Value as string);
					objectManifest.Add(obj.Key,true);
				}
				file.Close();
			}
		}
		else
		{
			System.IO.StreamWriter writer = info.CreateText();
			
			Dictionary<string,string> dict = new Dictionary<string,string>();
			
			System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(url);
			foreach(System.IO.FileInfo file in d.GetFiles())
			{
				if(file.Name != (name +"Index.json") && file.Name != (name +"Index_custom.json"))
				{
					using(StreamReader sr = file.OpenText())
					{
						string jsonBlob = sr.ReadToEnd();
						Dictionary<string,object> i = MiniJSON.Json.Deserialize(jsonBlob) as Dictionary<string,object>;
						if(i.ContainsKey("custom") && bool.Parse(i["custom"] as string))
						{
							_index.Add(file.Name.Replace(".json",""), i["name"] as string);
							objectManifest.Add(file.Name.Replace(".json",""), true); 
							dict.Add(file.Name.Replace(".json",""), i["name"] as string);
						}
						
						sr.Close();
					}
				}
			}
			
			string json = MiniJSON.Json.Serialize(dict);
			
			writer.WriteLine(json);
			
			writer.Close();
		}
	}
	
	public Dictionary<string, string> GetSubIndex(bool custom)
	{
		Dictionary<string,string> subIndex = new Dictionary<string, string>();
		foreach(KeyValuePair<string,bool> objectEntry in objectManifest)
		{
			if(objectEntry.Value == custom)
			{
				subIndex.Add(objectEntry.Key,index[objectEntry.Key]);
			}
		}
		return subIndex;
	}
	
	public bool SaveObject(type a, string filename)
	{		
		if (!objectManifest.ContainsKey(filename))
		{
			GameReference.reference.StartCoroutine(HelperFunctions.ConfirmationWindow("An Error has occured. You appear to be editing a corrupt file.", null));
			return false;
		}
		
		bool custom = objectManifest[filename];
		
		if (!GetSubIndex(custom).ContainsKey(filename))
		{
			GameReference.reference.StartCoroutine(HelperFunctions.ConfirmationWindow("An Error has occured. You appear to be editing a non-existant file.", null));
			return false;
		}
		
		bool tester = false;
		foreach(var i in GetSubIndex(custom))
		{
			if(i.Value == a.name && i.Key != filename)
				tester = true;
		}
		if(tester)
		{
			GameReference.reference.StartCoroutine(HelperFunctions.ConfirmationWindow("The chosen name already exists. Please enter a different name.", null));
			return false;
		}
		
		if(GetSubIndex(custom)[filename] != a.name)
		{
			Dictionary<string, string> tIndex = GetSubIndex(custom);
			tIndex[filename] = a.name;
			
			_index[filename] = a.name;
			
			string json = MiniJSON.Json.Serialize(tIndex);
			
			System.IO.FileInfo info = new System.IO.FileInfo(url + name + ((custom)?"Index_custom.json":"Index.json"));
			if(info.Exists)
			{
				info.Delete();
			}
			
			System.IO.StreamWriter writer = info.CreateText();
				
			writer.Write(json);
			
			writer.Close();
		}
		
		System.IO.FileInfo aInfo;
		
		aInfo = new System.IO.FileInfo(url + filename + ".json");
	
		if(aInfo.Exists)
		{
			aInfo.Delete();
		}
		
		System.IO.StreamWriter x = aInfo.CreateText();
		
		x.Write(a.ToJSON());
		
		x.Close();
		
		return true;
	}
	
	public void getNextValidName(ref string a, string namingFrom)
	{
		if(namingFrom == null)
			return;
		
		a = ValidName(a);
		
		while(objectManifest.ContainsKey(a))
		{
			int index = a.LastIndexOf("_");
			if(index > 0)
			{
				string numStr = a.Substring(index+1);
				int i;
				if(int.TryParse(numStr, out i))
				{
					i++;
					a = a.Remove(index);
					a += "_"+i.ToString();
				}
				else
				{
					a += "_2";
				}
			}
			else
			{
				a += "_2";
			}
		}
	}
	
	public type AddObject(type a, bool custom = false)
	{	
		getNextValidName(ref a.name, a.name);
		
		index.Add(ValidName(a.name), a.name);
		objectManifest.Add(ValidName(a.name), custom);
		
		a.fileName = ValidName(a.name);
		
		string json = MiniJSON.Json.Serialize(GetSubIndex(custom));
		
		System.IO.FileInfo info = new System.IO.FileInfo(url + name + ((custom)?"Index_custom.json":"Index.json"));
		if(info.Exists)
		{
			info.Delete();
		}
		
		System.IO.StreamWriter writer = info.CreateText();
			
		writer.Write(json);
		
		writer.Close();
		
		System.IO.FileInfo aInfo = new System.IO.FileInfo(url + ValidName(a.name) + ".json");
		
		if(aInfo.Exists)
		{
			aInfo.Delete();
		}
		
		System.IO.StreamWriter x = aInfo.CreateText();
		
		x.Write(a.ToJSON());
		
		x.Close();
		
		return a;
	}
	
	public void DeleteObject(string key)
	{
		if(!index.ContainsKey(ValidName(key)))
			return;
			
		bool custom = objectManifest[ValidName(key)];
		objectManifest.Remove(ValidName(key));
		index.Remove(ValidName(key));
		
		string json = MiniJSON.Json.Serialize(GetSubIndex(custom));
		
		System.IO.FileInfo info = new System.IO.FileInfo(url + name + ((custom)?"Index_custom.json":"Index.json"));
		if(info.Exists)
		{
			info.Delete();
		}
		
		System.IO.StreamWriter writer = info.CreateText();
			
		writer.Write(json);
		
		writer.Close();
		
		System.IO.FileInfo aInfo = new System.IO.FileInfo(url + ValidName(key) + ".json");
		
		if(aInfo.Exists)
		{
			aInfo.Delete();
		}
	}
	
	public type LoadObject(string key)
	{
		System.IO.FileInfo objInfo = new System.IO.FileInfo(url + ValidName(key) + ".json");
		Debug.Log("Loading File: " + objInfo.FullName);
		if(objInfo.Exists)
		{
			System.IO.StreamReader objFile = objInfo.OpenText();
			string objJson = objFile.ReadToEnd();
			objFile.Close();
			type obj = new type();
			obj.Load(objJson, key);
			return obj;
		}
		return null;
	}
}
